using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities;
using System.Workflow.ComponentModel.Design;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.ObjectModel;
using System.IO;
using System.Workflow.ComponentModel.Serialization;
using System.Xml;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Workflow.Activities.Rules;
using System.Workflow.Activities.Rules.Design;

namespace Crab.WorkflowClient
{
    public partial class WorkflowDesignerControl : UserControl, IDisposable, IServiceProvider, IServiceContainer, ISite
    {
        private WorkflowView workflowView;
        private WorkflowDesignSurface designSurface;
        private WorkflowLoader loader;
        private ServiceContainer container;
        private string typeName;
        private string nameSpace;
        private MainForm parent;

        //private AmountProperty amountProperty;

        public WorkflowDesignerControl(MainForm parent)
        {
            InitializeComponent();
            container = new ServiceContainer();
            this.parent = parent;

            WorkflowTheme.CurrentTheme.ReadOnly = false;
            WorkflowTheme.CurrentTheme.AmbientTheme.ShowConfigErrors = false;
            WorkflowTheme.CurrentTheme.ReadOnly = true;
        }



        public string NameSpace
        {
            get { return nameSpace; }
            set { nameSpace = value; }
        }

        public string TypeName
        {
            get { return typeName; }
            set { typeName = value; }
        }

        public string Xoml
        {
            get
            {
                string xoml = string.Empty;
                if (this.loader != null)
                {
                    try
                    {
                        this.loader.Flush();
                        xoml = this.loader.XomlFile;
                    }
                    catch
                    {
                    }
                }
                return xoml;
            }

            set
            {
                try
                {
                    if (!String.IsNullOrEmpty(value))
                        LoadWorkflow(value, null);
                }
                catch
                {
                }
            }
        }


        public WorkflowView WorkflowView
        {
            get { return this.workflowView; }
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                UnloadWorkflow();
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        new public object GetService(Type serviceType)
        {
            object service = null;
            if (this.workflowView != null)
            {
                service = ((IServiceProvider)this.workflowView).GetService(serviceType);
                if (service == null)
                {
                    service = container.GetService(serviceType);
                }
            }
            else
            {
                service = container.GetService(serviceType);
            }
            return service;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            //ShowDefaultWorkflow();
        }

        public void LoadWorkflow(string xoml, string supportAssemblyPath)
        {
            SuspendLayout();

            WorkflowDesignSurface designSurface = new WorkflowDesignSurface(this);
            WorkflowLoader loader = new WorkflowLoader();
            loader.XomlFile = xoml;
            loader.SupportAssemblyPath = supportAssemblyPath;
            designSurface.BeginLoad(loader);

            IDesignerHost designerHost = designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost != null && designerHost.RootComponent != null)
            {
                IRootDesigner rootDesigner = designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;
                if (rootDesigner != null)
                {
                    UnloadWorkflow();

                    this.designSurface = designSurface;
                    this.loader = loader;
                    this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
                    this.splitContainer1.Panel1.Controls.Add(this.workflowView);
                    this.workflowView.Dock = DockStyle.Fill;
                    this.workflowView.TabIndex = 1;
                    this.workflowView.TabStop = true;
                    this.workflowView.HScrollBar.TabStop = false;
                    this.workflowView.VScrollBar.TabStop = false;
                    this.workflowView.Focus();
                    this.propertyGrid.Site = designerHost.RootComponent.Site;

                    ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
                    if (selectionService != null)
                        selectionService.SelectionChanged += new EventHandler(OnSelectionChanged);

                    WorkflowMenuCommandService menuService = GetService(typeof(IMenuCommandService)) as WorkflowMenuCommandService;

                    if (menuService != null)
                        menuService.MenuClicked += new EventHandler(menuService_MenuClicked);
                }
            }

            ResumeLayout(true);

        }

        void menuService_MenuClicked(object sender, EventArgs e)
        {
            MenuItem menuItem = sender as MenuItem;
            if (menuItem != null && !string.IsNullOrEmpty(menuItem.Tag.ToString()))
            {
                Activity act = null;
                if (menuItem.Tag.ToString() == "AddSendMail")
                {
                    act = new Crab.Workflow.Activities.SendMailActivity();
                    AddActivity(act);
                }
                else if (menuItem.Tag.ToString() == "AddReview")
                {
                    act = new Crab.Workflow.Activities.ReviewActivity();
                    AddActivity(act);
                }
                else if (menuItem.Tag.ToString() == "AddIfElse")
                {
                    act = new IfElseActivity();
                    (act as CompositeActivity).Activities.Add(new IfElseBranchActivity());
                    AddActivity(act);
                }
                else if (menuItem.Tag.ToString() == "Delete")
                {
                    RemoveSelectedActivity();
                }
            }
        }

        public void LoadWorkflow(string xoml, string supportAssemblyPath, string tenantId,string userId)
        {
            SuspendLayout();

            WorkflowDesignSurface designSurface = new WorkflowDesignSurface(this);
            WorkflowLoader loader = new WorkflowLoader();
            loader.XomlFile = xoml;
            loader.SupportAssemblyPath = supportAssemblyPath;

            designSurface.BeginLoad(loader);

            IDesignerHost designerHost = designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost != null && designerHost.RootComponent != null)
            {
                IRootDesigner rootDesigner = designerHost.GetDesigner(designerHost.RootComponent) as IRootDesigner;
                if (rootDesigner != null)
                {
                    UnloadWorkflow();

                    this.designSurface = designSurface;
                    this.loader = loader;
                    this.workflowView = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
                    this.splitContainer1.Panel1.Controls.Add(this.workflowView);
                    this.workflowView.Dock = DockStyle.Fill;
                    this.workflowView.TabIndex = 1;
                    this.workflowView.TabStop = true;
                    this.workflowView.HScrollBar.TabStop = false;
                    this.workflowView.VScrollBar.TabStop = false;
                    this.workflowView.Focus();
                    this.propertyGrid.Site = designerHost.RootComponent.Site;

                    ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
                    if (selectionService != null)
                        selectionService.SelectionChanged += new EventHandler(OnSelectionChanged);

                    WorkflowMenuCommandService menuService = GetService(typeof(IMenuCommandService)) as WorkflowMenuCommandService;

                    if (menuService != null)
                        menuService.MenuClicked += new EventHandler(menuService_MenuClicked);
                }
            }

            ResumeLayout(true);

        }
        private void UnloadWorkflow()
        {
            IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (designerHost != null && designerHost.Container.Components.Count > 0)
                WorkflowLoader.DestroyObjectGraphFromDesignerHost(designerHost, designerHost.RootComponent as Activity);

            ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
            if (selectionService != null)
                selectionService.SelectionChanged -= new EventHandler(OnSelectionChanged);

            WorkflowMenuCommandService menuService = GetService(typeof(IMenuCommandService)) as WorkflowMenuCommandService;

            if (menuService != null)
                menuService.MenuClicked -= new EventHandler(menuService_MenuClicked);

            if (this.designSurface != null)
            {
                this.designSurface.Dispose();
                this.designSurface = null;
            }

            if (this.workflowView != null)
            {
                Controls.Remove(this.workflowView);
                this.workflowView.Dispose();
                this.workflowView = null;
            }
        }

        public void ShowDefaultWorkflow()
        {
            SequentialWorkflowActivity workflow = new SequentialWorkflowActivity();
            workflow.Name = "Workflow1";
            workflow.SetValue(WorkflowMarkupSerializer.XClassProperty, "foo.Workflow1");
            XmlWriter xmlWriter = XmlTextWriter.Create(@"Myfile.xoml");
            WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
            serializer.Serialize(xmlWriter, workflow);
            xmlWriter.Close();
            LoadWorkflow(@"Myfile.xoml", null);
        }

        private void OnSelectionChanged(object sender, EventArgs e)
        {
            Activity acivity = GetSelectedActivity();
            //if (acivity is SequentialWorkflowActivity)
             //   this.propertyGrid.SelectedObject = null;
            //else
                this.propertyGrid.SelectedObject = acivity;
        }

        public Activity GetSelectedActivity()
        {
            ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService));

            if (selectionService != null && selectionService.PrimarySelection is Activity)
            {
                return selectionService.PrimarySelection as Activity;
            }

            return null;
        }

        //public void InvokeStandardCommand(CommandID cmd)
        //{
        //    IMenuCommandService menuService = GetService(typeof(IMenuCommandService)) as IMenuCommandService;
        //    if (menuService != null)
        //        menuService.GlobalInvoke(cmd);
        //}

        /// <summary>
        /// Save the file. We also refresh the type provider when we save the file
        /// </summary>
        /// <param name="filePath">The path of the file to save</param>
        public void Save(string filePath)
        {
            if (this.loader != null)
            {
                if (filePath != null && filePath != string.Empty)
                    this.loader.XomlFile = filePath;
                this.loader.Flush();
            }
        }

        //public bool ChangeActivity(Activity act)
        //{

        //    IServiceProvider serviceProvider = designSurface as IServiceProvider;
        //    ISelectionService selectionService = (ISelectionService)serviceProvider.GetService(typeof(ISelectionService));
        //    if (selectionService != null && selectionService.PrimarySelection is Activity)
        //    {

        //        Activity ActivityComponent = (Activity)selectionService.PrimarySelection;

        //        int selectedIndex = ActivityComponent.Parent.Activities.IndexOf(ActivityComponent);
        //        ActivityComponent.Parent.Activities.Insert(selectedIndex, act);
        //        ActivityComponent.Parent.Activities.Remove(ActivityComponent);
        //        workflowView.Update();
        //    }

        //    return true;
        //}

        public bool AddActivity(Activity act)
        {
            IServiceProvider serviceProvider = designSurface as IServiceProvider;
            ISelectionService selectionService = (ISelectionService)serviceProvider.GetService(typeof(ISelectionService));
            if (selectionService != null && selectionService.PrimarySelection != null 
                && selectionService.PrimarySelection is System.Workflow.ComponentModel.Design.ConnectorHitTestInfo)
            {
                System.Workflow.ComponentModel.Design.ConnectorHitTestInfo hti = (System.Workflow.ComponentModel.Design.ConnectorHitTestInfo)selectionService.PrimarySelection;
                List<Activity> list = new List<Activity>();
                list.Add(act);

                ReadOnlyCollection<Activity> acts = new ReadOnlyCollection<Activity>(list);
                if (hti.AssociatedDesigner != null)
                {
                    CompositeActivityDesigner root = hti.AssociatedDesigner as CompositeActivityDesigner;
                    if (root.CanInsertActivities(hti, acts))
                    {
                        CompositeActivityDesigner.InsertActivities(root, hti, acts, "");
                    }
                }

                workflowView.Update();
            }

            return true;
        }

        public bool RemoveSelectedActivity()
        {
            if (MessageBox.Show("Are you sure to delete the activity?", "Confirm", MessageBoxButtons.YesNo)
                        != DialogResult.Yes)
                return false;
            IServiceProvider serviceProvider = designSurface as IServiceProvider;
            ISelectionService selectionService = (ISelectionService)serviceProvider.GetService(typeof(ISelectionService));
            if (selectionService != null && selectionService.PrimarySelection != null)
            {
                Activity ActivityComponent = (Activity)selectionService.PrimarySelection;
                ActivityComponent.Parent.Activities.Remove(ActivityComponent);
                workflowView.Update();

                this.propertyGrid.SelectedObject = null;
            }

            return true;
        }

        void propertyGrid_GotFocus(object sender, System.EventArgs e)
        {
            this.Save(this.loader.XomlFile);
        }

        #region ISite Members

        public IComponent Component
        {
            get { return this; }
        }

        public new bool DesignMode
        {
            get { return true; }
        }

        #endregion

        #region IServiceContainer Members

        public void AddService(Type serviceType, ServiceCreatorCallback callback, bool promote)
        {
            container.AddService(serviceType, callback, promote);
        }

        public void AddService(Type serviceType, ServiceCreatorCallback callback)
        {
            container.AddService(serviceType, callback);
        }

        public void AddService(Type serviceType, object serviceInstance, bool promote)
        {
            container.AddService(serviceType, serviceInstance, promote);
        }

        public void AddService(Type serviceType, object serviceInstance)
        {
            container.AddService(serviceType, serviceInstance);
        }

        public void RemoveService(Type serviceType, bool promote)
        {
            container.RemoveService(serviceType, promote);
        }

        public void RemoveService(Type serviceType)
        {
            container.RemoveService(serviceType);
        }

        #endregion

    }

}
